#include <TI_CC2500.h>
#include <msp430x14x.h>
#include "constants.h"

void TI_CC_Wait(unsigned int cycles)
{
  while(cycles>15)                          // 15 cycles consumed by overhead
    cycles = cycles - 6;                    // 6 cycles consumed each iteration
}

void TI_CC_SPISetup(void)
{
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         //P5OUT |= 0x01
  TI_CC_CSn_PxDIR |= TI_CC_CSn_PIN;         // /CS disable

  ME2 |= USPIE1;                            // Enable USART1 SPI mode
  UCTL1 |= CHAR + SYNC + MM + SWRST;        // 8-bit SPI Master **SWRST** old : no SWRST
  UTCTL1 |= CKPL + SSEL0 + STC;             // SMCLK, 3-pin mode old included: SSEL1 + SSEL0
  UBR01 = 0x02;                             // UCLK/2 
  UBR11 = 0x00;                             // 0 
  UMCTL1 = 0x00;                            // No modulation 
  TI_CC_SPI_USART1_PxSEL |= TI_CC_SPI_USART1_SIMO | TI_CC_SPI_USART1_SOMI | TI_CC_SPI_USART1_UCLK;
                                            // SPI option select
  TI_CC_SPI_USART1_PxDIR |= TI_CC_SPI_USART1_SIMO + TI_CC_SPI_USART1_UCLK;
                                            // SPI TXD out direction
  UCTL1 &= ~SWRST;                          // Initialize USART state machine

  //added code to enable interrupt at 2.4
  P2IES |= 0x10;       // Int on falling edge (end of pkt)
  P2IFG &= ~0x10;      // Clear flag
  P2IE |= 0x10;        // Enable int on end of packet
}

void TI_CC_SPIWriteReg(char addr, char value)
{
    TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;      // /CS enable
    while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
    IFG2 &= ~URXIFG1;                       // Clear flag
    U1TXBUF = addr;                         // Send address
    while (!(IFG2&URXIFG1));                // Wait for TX to finish
    IFG2 &= ~URXIFG1;                       // Clear flag
    U1TXBUF = value;                        // Load data for TX after addr
    while (!(IFG2&URXIFG1));                // Wait for end of addr TX
    TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;       // /CS disable
}

void TI_CC_SPIWriteBurstReg(char addr, char *buffer, char count)
{
    char i;

    TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;      // /CS enable
    while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
    U1TXBUF = addr | TI_CCxxx0_WRITE_BURST; // Send address
    while (!(IFG2&UTXIFG1));                // Wait for TX to finish
    for (i = 0; i < count; i++)
    {
      U1TXBUF = buffer[i];                  // Send data
      while (!(IFG2&UTXIFG1));              // Wait for TX to finish
    }
    IFG2 &= ~URXIFG1;
    while(!(IFG2&URXIFG1));
    TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;       // /CS disable
}

char TI_CC_SPIReadReg(char addr)
{
  char x;

  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;        // /CS enable
  while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
  IFG2 &= ~URXIFG1;                         // Clear flag set during addr TX
  U1TXBUF = (addr | TI_CCxxx0_READ_SINGLE); // Send address
  while (!(IFG2&URXIFG1));                  // Wait for TXBUF ready
  IFG2 &= ~URXIFG1;                         // Clear flag set during addr TX
  U1TXBUF = 0;                              // Load dummy byte for TX after addr
  while (!(IFG2&URXIFG1));                  // Wait for end of dummy byte TX
  x = U1RXBUF;                              // Read data
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         // /CS disable

  return x;
}

void TI_CC_SPIReadBurstReg(char addr, char *buffer, char count)
{
  unsigned int i;

  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;        // /CS enable
  while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
  IFG2 &= ~URXIFG1;                         // Clear flag
  U1TXBUF = (addr | TI_CCxxx0_READ_BURST);  // Send address
  while (!(IFG2&UTXIFG1));                  // Wait for TXBUF ready
  U1TXBUF = 0;                              // Dummy write to read 1st data byte
  // Addr byte is now being TX'ed, with dummy byte to follow immediately after
  while (!(IFG2&URXIFG1));                  // Wait for end of addr byte TX
  IFG2 &= ~URXIFG1;                         // Clear flag
  while (!(IFG2&URXIFG1));                  // Wait for end of 1st data byte TX
  // First data byte now in RXBUF
  for (i = 0; i < (count-1); i++)
  {
    U1TXBUF = 0;                            //Initiate next data RX, meanwhile..
    buffer[i] = U1RXBUF;                    // Store data from last data RX
    while (!(IFG2&URXIFG1));                // Wait for end of data RX
  }
  buffer[count-1] = U1RXBUF;                // Store last RX byte in buffer
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         // /CS disable
}

char TI_CC_SPIReadStatus(char addr)
{
  char x;

  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;        // /CS enable
  while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
  IFG2 &= ~URXIFG1;                         // Clear flag set during last write
  U1TXBUF = (addr | TI_CCxxx0_READ_BURST);  // Send address
  while (!(IFG2&URXIFG1));                  // Wait for TX to finish
  IFG2 &= ~URXIFG1;                         // Clear flag set during last write
  U1TXBUF = 0;                              // Dummy write so we can read data
  while (!(IFG2&URXIFG1));                  // Wait for RX to finish
  x = U1RXBUF;                              // Read data
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         // /CS disable

  return x;
}

void TI_CC_SPIStrobe(char strobe)
{
  TI_CC_CSn_PxOUT &= ~TI_CC_CSn_PIN;        // /CS enable
  while (TI_CC_SPI_USART1_PxIN&TI_CC_SPI_USART1_SOMI);// Wait for CCxxxx ready
  U1TXBUF = strobe;                         // Send strobe
  // Strobe addr is now being TX'ed
  IFG2 &= ~URXIFG1;                         // Clear flag
  while (!(IFG2&URXIFG1));                  // Wait for end of addr TX
  TI_CC_CSn_PxOUT |= TI_CC_CSn_PIN;         // /CS disable
}

//-----------------------------------------------------------------------------
//  void RFSendPacket(char *txBuffer, char size)
//
//  DESCRIPTION:
//  This function transmits a packet with length up to 63 bytes.  To use this
//  function, GD00 must be configured to be asserted when sync word is sent and
//  de-asserted at the end of the packet, which is accomplished by setting the
//  IOCFG0 register to 0x06, per the CCxxxx datasheet.  GDO0 goes high at
//  packet start and returns low when complete.  The function polls GDO0 to
//  ensure packet completion before returning.
//
//  ARGUMENTS:
//      char *txBuffer
//          Pointer to a buffer containing the data to be transmitted
//
//      char size
//          The size of the txBuffer
//-----------------------------------------------------------------------------
void RFSendPacket(char *txBuffer, char size)
{
    TI_CC_SPIWriteBurstReg(TI_CCxxx0_TXFIFO, txBuffer, size); // Write TX data
    TI_CC_SPIStrobe(TI_CCxxx0_STX);         // Change state to TX, initiating
                                            // data transfer

    while (!(TI_CC_GDO0_PxIN&TI_CC_GDO0_PIN));
                                            // Wait GDO0 to go hi -> sync TX'ed
    while (TI_CC_GDO0_PxIN&TI_CC_GDO0_PIN);
                                            // Wait GDO0 to clear -> end of pkt
}



//-----------------------------------------------------------------------------
//  char RFReceivePacket(char *rxBuffer, char *length)
//
//  DESCRIPTION:
//  Receives a packet of variable length (first byte in the packet must be the
//  length byte).  The packet length should not exceed the RXFIFO size.  To use
//  this function, APPEND_STATUS in the PKTCTRL1 register must be enabled.  It
//  is assumed that the function is called after it is known that a packet has
//  been received; for example, in response to GDO0 going low when it is
//  configured to output packet reception status.
//
//  The RXBYTES register is first read to ensure there are bytes in the FIFO.
//  This is done because the GDO signal will go high even if the FIFO is flushed
//  due to address filtering, CRC filtering, or packet length filtering.
//
//  ARGUMENTS:
//      char *rxBuffer
//          Pointer to the buffer where the incoming data should be stored
//      char *length
//          Pointer to a variable containing the size of the buffer where the
//          incoming data should be stored. After this function returns, that
//          variable holds the packet length.
//
//  RETURN VALUE:
//      char
//          0x80:  CRC OK
//          0x00:  CRC NOT OK (or no pkt was put in the RXFIFO due to filtering)
//-----------------------------------------------------------------------------
char RFReceivePacket(char *rxBuffer, char *length) {
  char status[2];
  char pktLen;

  char x = TI_CC_SPIReadStatus(TI_CCxxx0_RXBYTES);

//  println("Status for RXBYTES is: ");
//  printHex(x);

  if ((x & TI_CCxxx0_NUM_RXBYTES)) {
    pktLen = TI_CC_SPIReadReg(TI_CCxxx0_RXFIFO); // Read length byte

    if (pktLen <= *length)                  // If pktLen size <= rxBuffer
    {
      TI_CC_SPIReadBurstReg(TI_CCxxx0_RXFIFO, rxBuffer, pktLen); // Pull data
      *length = pktLen;                     // Return the actual size
      TI_CC_SPIReadBurstReg(TI_CCxxx0_RXFIFO, status, 2);
                                            // Read appended status bytes
      return (char)(status[TI_CCxxx0_LQI_RX]&TI_CCxxx0_CRC_OK);

    }else{                                  // Return CRC_OK bit   
      *length = pktLen;                     // Return the large size
      TI_CC_SPIStrobe(TI_CCxxx0_SFRX);      // Flush RXFIFO
      return 0;                             // Error
    }
  }else
      return 0;                             // Error
}//end
